using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;

namespace CombatTracker.Controls
{
  public class CombatListView : ListView
  {
    private ListViewItem _previousItem;

    public ListViewItem HoverItem
    {
      get { return _previousItem; }
    }

    public CombatListView() : base()
    {
      _previousItem = null;
    }

    protected override void OnDragOver(DragEventArgs drgevent)
    {
      if (base.Items.Count > 0)
      {
        Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y));
        ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);

        Graphics g = this.CreateGraphics();

        if (hoverItem == null)
        {
          drgevent.Effect = DragDropEffects.Move;

          if (_previousItem != null)
          {
            _previousItem = null;
            Invalidate();
          }

          hoverItem = base.Items[base.Items.Count - 1];

          if (this.View == View.Details || this.View == View.List)
          {
            g.DrawLine(new Pen(Color.Black, 2), new Point(hoverItem.Bounds.X,
             hoverItem.Bounds.Y + hoverItem.Bounds.Height),
             new Point(hoverItem.Bounds.X +
             this.Bounds.Width, hoverItem.Bounds.Y +
             hoverItem.Bounds.Height));
            g.FillPolygon(new SolidBrush(Color.Black),
             new Point[] {new Point(hoverItem.Bounds.X, 
     hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), 
     new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + 
     hoverItem.Bounds.Height), 
     new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 
     hoverItem.Bounds.Height + 5)});
            g.FillPolygon(new SolidBrush(Color.Black),
             new Point[] {new Point(this.Bounds.Width - 4, 
     hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), 
     new Point(this.Bounds.Width - 9, 
     hoverItem.Bounds.Y + hoverItem.Bounds.Height), 
     new Point(this.Bounds.Width - 4, 
     hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5)});
          }
          else
          {
            g.DrawLine(new Pen(Color.Black, 2),
             new Point(hoverItem.Bounds.X +
             hoverItem.Bounds.Width, hoverItem.Bounds.Y),
             new Point(hoverItem.Bounds.X +
             hoverItem.Bounds.Width, hoverItem.Bounds.Y +
             hoverItem.Bounds.Height));
            g.FillPolygon(new SolidBrush(Color.Black),
             new Point[] {new Point(hoverItem.Bounds.X + 
     hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y), 
     new Point(hoverItem.Bounds.X + 
     hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y), 
     new Point(hoverItem.Bounds.X + 
     hoverItem.Bounds.Width, hoverItem.Bounds.Y + 5)});
            g.FillPolygon(new SolidBrush(Color.Black),
             new Point[] {new Point(hoverItem.Bounds.X + 
     hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y + 
     hoverItem.Bounds.Height), 
     new Point(hoverItem.Bounds.X + 
     hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y + 
     hoverItem.Bounds.Height), 
     new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, 
     hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)});
          }

          base.OnDragOver(drgevent);

          return;
        }

        if ((_previousItem != null &&
          _previousItem != hoverItem) || _previousItem == null)
        {
          this.Invalidate();
        }

        _previousItem = hoverItem;

        if (this.View == View.Details || this.View == View.List)
        {
          g.DrawLine(new Pen(Color.Black, 2), new Point(hoverItem.Bounds.X,
           hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + this.Bounds.Width,
           hoverItem.Bounds.Y));
          g.FillPolygon(new SolidBrush(Color.Black),
           new Point[] {new Point(hoverItem.Bounds.X, 
    hoverItem.Bounds.Y - 5), new Point(hoverItem.Bounds.X + 5, 
    hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, 
    hoverItem.Bounds.Y + 5)});
          g.FillPolygon(new SolidBrush(Color.Black),
           new Point[] {new Point(this.Bounds.Width - 4, 
    hoverItem.Bounds.Y - 5), new Point(this.Bounds.Width - 9, 
    hoverItem.Bounds.Y), new Point(this.Bounds.Width - 4, 
    hoverItem.Bounds.Y + 5)});
        }
        else
        {
          g.DrawLine(new Pen(Color.Black, 2),
           new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y),
           new Point(hoverItem.Bounds.X,
           hoverItem.Bounds.Y + hoverItem.Bounds.Height));
          g.FillPolygon(new SolidBrush(Color.Black),
           new Point[] {new Point(hoverItem.Bounds.X - 5, 
    hoverItem.Bounds.Y), 
    new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), 
    new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5)});
          g.FillPolygon(new SolidBrush(Color.Black),
           new Point[] {new Point(hoverItem.Bounds.X - 5, 
    hoverItem.Bounds.Y + hoverItem.Bounds.Height), 
    new Point(hoverItem.Bounds.X + 5, 
    hoverItem.Bounds.Y + hoverItem.Bounds.Height), 
    new Point(hoverItem.Bounds.X, 
    hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)});

        }

        foreach (ListViewItem itemToMove in base.SelectedItems)
        {
          if (itemToMove.Index == hoverItem.Index)
          {
            drgevent.Effect = DragDropEffects.None;
            hoverItem.EnsureVisible();
            return;
          }
        }

        hoverItem.EnsureVisible();
      }

      base.OnDragOver(drgevent);
    }

    protected override void OnLostFocus(EventArgs e)
    {
      // reset the selected items background and remove the previous item
      ResetOutOfRange();

      Invalidate();

      // call the OnLostFocus event
      base.OnLostFocus(e);
    }

    protected override void OnDragLeave(EventArgs e)
    {
      // reset the selected items background and remove the previous item
      ResetOutOfRange();

      Invalidate();

      // call the base OnDragLeave event
      base.OnDragLeave(e);
    }

    private void ResetOutOfRange()
    {
      // determine if the previous item exists,
      // if it does, reset the background and release 
      // the previous item
      if (_previousItem != null)
      {
        _previousItem = null;
      }

    }
  }
}
